#ifndef __ovip_third_nutshell_simple_uart__
#define __ovip_third_nutshell_simple_uart__
#include "nutshell_simplebus.h"
#include "xspcomm/xclock.h"
#include "openvip/mem.h"
#include "xspcomm/xcoroutine.h"

namespace ovip {
    class SimpleUART
    {
        xspcomm::XClock *clk;
        u_int64_t read_addr = 0;
        u_int64_t read_offs = 0;
        u_int64_t wdat_addr = 0;
        u_int64_t wdat_offs = 100;
        int read_index      = 0;
        u_int8_t default_value = 0;

    public:
        std::string mName;
        std::string mPrefix;
        SimpleBusWrapper mBus;
        SimpleUART(xspcomm::XClock &clock, std::string name, xspcomm::XPort &port,
                  std::string prefix = "", u_char default_value = 0):
            mBus(port, prefix), default_value(default_value)
        {
            this->mName = name;
            this->clk   = &clock;
            this->clk->StepRis([this](u_int64_t c, void *args) {
                // init
                this->mBus.port["resp_valid"] = 0;
                if (this->mBus.port["req_valid"] == 1) {
                    if(this->mBus.IsReqRead()){
                        auto addr = this->mBus.port["req_bits_addr"];
                        this->mBus.RespWriteData(this->mBus.cmd_readLast, this->default_value);
                        return;
                    }
                    if (this->mBus.IsReqWrite()) {
                        this->mBus.RespWriteData(this->mBus.cmd_writeResp, 0);
                        u_int64_t data = this->mBus.port["req_bits_wdata"].U();
                        this->putc(((char *)&data)[0]);
                    } else {
                        Assert(false, "%s.request.cmd (%ld) is not supported!",
                               this->mName.c_str(),
                               this->mBus.port["req_bits_cmd"].U());
                    }
                }
            });

            // always be req-ready and resp-invalid
            this->mBus.port["req_ready"]  = 1;
            this->mBus.port["resp_valid"] = 0;
        }
        virtual void putc(unsigned char c){
            printf("%c", c);
        }
    };

} // namespace ovip

#endif
